package net.kem.android.positioner;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Enumeration;

import android.util.Log;

public class TalkToServer {
	private static InetAddress localIpAddress;
	static String talkToWebServer(String host, int port, String payload, boolean expectResponse) throws IOException {
		String response;
		HttpURLConnection urlConnection = null;
		try {
			URL url = new URL(host + ":" + port);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.setDoOutput(true);
			urlConnection.setChunkedStreamingMode(0);

			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(urlConnection.getOutputStream()));
			BufferedReader br = expectResponse? new BufferedReader(new InputStreamReader(urlConnection.getInputStream())): null;

			response = talkToServer(bw, br, payload);
			return response;
		} finally {
			if(urlConnection != null) {
				urlConnection.disconnect();
			}
		}
	}

	static String talkToServer(String host, int port, String payload, boolean expectResponse) throws UnknownHostException, IOException {
		Socket socket = null;
		try {
			SocketAddress sockaddr = new InetSocketAddress(host, port);
			socket = new Socket();
			socket.connect(sockaddr, 5000);
			socket.setSoTimeout(10000); // wait up to 10 seconds for response.

			String response = talkToServer(socket, payload, expectResponse);
			return response;
		} finally {
			if (socket != null) {
				try {socket.getInputStream().close();} catch (IOException ignore) {}
				try {socket.getOutputStream().close();} catch (IOException ignore) {}
				try {socket.close();} catch (IOException ignore) {}
			}
		}
	}

	public static String talkToServer(Socket socket, String payload, boolean expectResponse) throws IOException {
		String response;
		socket.setSoTimeout(10000); // wait up to 10 seconds for response.

		BufferedWriter bw = payload==null? null: new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), 128);
		BufferedReader br = expectResponse? new BufferedReader(new InputStreamReader(socket.getInputStream())): null;

		response = talkToServer(bw, br, payload);
		return response;
	}

	static String talkToServer(BufferedWriter bw, BufferedReader br, String payload) throws IOException {
		String response;
		DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);

		if(bw != null && payload != null) {
			bw.write(payload);
			bw.flush();
			Log.d("talkToServer", ">> " + payload);
		}

		if(br != null) {
			response = br.readLine();
			Log.d("talkToServer", "<< " + response + ' ' + df.format(new Date()));
		} else {
			response = null;
		}
		return response;
	}

	public static InetAddress getLocalIpAddress(boolean forceRefresh) {
		if(localIpAddress == null || forceRefresh) {
			try {
				for(Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
					NetworkInterface intf = en.nextElement();
					for(Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
						InetAddress inetAddress = enumIpAddr.nextElement();
						if(!inetAddress.isLoopbackAddress()) {
							localIpAddress = inetAddress;//.getHostAddress().toString();
							return localIpAddress;
						}
					}
				}
			} catch (SocketException ex) {
				localIpAddress = null;
				Log.e("talkToServer", ex.toString());
			}
		}
	    return localIpAddress;
	}
}